home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 49 / Amiga Format CD49 (2000-01-17)(Future Publishing)(GB)(Track 1 of 3)[!][issue 2000-02].iso / +system+ / tools / sound / ahi / developer / devloper.lzx / examples / Device / AHI-Handler / main.c < prev    next >
C/C++ Source or Header  |  1979-06-21  |  31KB  |  1,143 lines

  1. /* $Id: main.c,v 4.2 1997/04/09 01:55:32 lcs Exp $
  2.  * $Log: main.c,v $
  3.  * Revision 4.2  1997/04/09  01:55:32  lcs
  4.  * Much improved error handling.
  5.  *
  6.  * Revision 4.1  1997/04/02  22:46:37  lcs
  7.  * Bumped to version 4
  8.  *
  9.  * Revision 1.8  1997/03/27  12:11:25  lcs
  10.  * Never mind! Bah.
  11.  *
  12.  * Revision 1.7  1997/03/26  13:32:43  lcs
  13.  * Added UNIT to the template, and set taskpri to 5.
  14.  *
  15.  * Revision 1.6  1997/02/01  14:10:08  lcs
  16.  * A couple of bugs fixed.
  17.  *
  18.  * Revision 1.5  1997/01/29  15:44:49  lcs
  19.  * It's "finished"!
  20.  *
  21.  * Revision 1.4  1997/01/24  23:20:47  lcs
  22.  * Writing seem to work too...
  23.  *
  24.  * Revision 1.3  1997/01/23  19:55:50  lcs
  25.  * Added AIFF and AIFC saving.
  26.  *
  27.  * Revision 1.2  1997/01/21  23:56:21  lcs
  28.  * Reading seem to work okay now.
  29.  *
  30.  * Revision 1.1  1997/01/17  23:34:28  lcs
  31.  * Initial revision
  32.  *
  33.  */
  34.  
  35. /*
  36.  * This code is written using DICE, and is based on the DosHan example
  37.  * source code that came with the compiler. Not all comments are mine,
  38.  * by the way... 
  39.  *
  40.  * Done by Martin Blom 1997. Public Domain.
  41.  *
  42.  */
  43.  
  44.  
  45. #include <exec/types.h>
  46. #include <exec/nodes.h>
  47. #include <exec/ports.h>
  48. #include <exec/memory.h>
  49. #include <dos/dos.h>
  50. #include <dos/dosextens.h>
  51. #include <dos/filehandler.h>
  52. #include <dos/rdargs.h>
  53.  
  54. #include <devices/ahi.h>
  55. #include <proto/ahi.h>
  56.  
  57. #include <clib/exec_protos.h>
  58. #include <clib/alib_protos.h>
  59. #include <clib/dos_protos.h>
  60. #include <clib/utility_protos.h>
  61.  
  62. #include <stdio.h>
  63. #include <stdarg.h>
  64. #include <stdlib.h>
  65. #include <string.h>
  66.  
  67. #include "main.h"
  68.  
  69.  
  70. /*
  71.  *  Prototypes
  72.  */
  73.  
  74. LONG PlayAndSwap(struct HandlerData *, LONG);
  75. long extended2long(extended *);
  76. void ulong2extended (ULONG, extended *);
  77. void FillAIFFheader(struct HandlerData *);
  78. void FillAIFCheader(struct HandlerData *);
  79. LONG ReadCOMMchunk(struct HandlerData *, UBYTE *, LONG);
  80. long AllocAudio(int);
  81. void FreeAudio(void);
  82. long ParseArgs(struct HandlerData *, char *);
  83. long InitHData(struct HandlerData *);
  84. void FreeHData(struct HandlerData *);
  85. void returnpacket (struct DosPacket *);
  86. void Initialize (void);
  87. void UnInitialize (void);
  88.  
  89.  
  90. /*
  91.  *  Some macros
  92.  */
  93.  
  94. #define min(a,b) ((a)<=(b)?(a):(b))
  95. #define DOS_TRUE    -1
  96. #define DOS_FALSE   0
  97. #define BTOC(bptr)  ((void *)((long)(bptr) << 2))
  98. #define CTOB(cptr)  ((BPTR)(((long)cptr) >> 2))
  99.  
  100.  
  101. /*
  102.  *  My debug stuff....
  103.  */
  104.  
  105. #define HIT(x) {char *a=NULL; *a=x;}
  106. void kprintf(char *, ...);
  107.  
  108.  
  109. /*
  110.  *  Global variables
  111.  */
  112.  
  113. const static char ID[] = "$VER: AHI-Handler 4.2 (9.4.97)\r\n";
  114.  
  115. struct List        HanList;
  116. struct DeviceNode *DevNode;
  117. struct MsgPort    *PktPort;
  118. int                AllocCnt;
  119. BOOL               Running;
  120.  
  121. struct MsgPort    *AHImp     = NULL;
  122. struct AHIRequest *AHIio     = NULL;
  123. BYTE               AHIDevice = -1;
  124. struct Library    *AHIBase;
  125.  
  126. struct AIFCHeader AIFCHeader = {
  127.   ID_FORM, NULL, ID_AIFC,
  128.   ID_FVER, sizeof(FormatVersionHeader), {
  129.     AIFCVersion1
  130.   },
  131.   ID_COMM, sizeof(ExtCommonChunk), {
  132.     0,
  133.     0,
  134.     0,
  135.     {0},
  136.     NO_COMPRESSION,
  137.     sizeof("not compressed")-1,
  138.     'n','o','t',' ','c','o','m','p','r','e','s','s','e','d'
  139.   },
  140.   ID_SSND, NULL, {0,0}
  141. };
  142.  
  143. struct AIFFHeader AIFFHeader = {
  144.   ID_FORM, NULL, ID_AIFF,
  145.   ID_COMM, sizeof(CommonChunk),{
  146.     0,
  147.     0,
  148.     0,
  149.     {0}
  150.   },
  151.   ID_SSND, NULL, {0,0}
  152. };
  153.  
  154.  
  155. /******************************************************************************
  156. **** Entry ********************************************************************
  157. ******************************************************************************/
  158.  
  159. /*
  160.  *  Note that we use the _main entry point.  Also notice that we do not
  161.  *  need to open any libraries.. they are openned for us via DICE's
  162.  *  unique auto-library-open ability.
  163.  */
  164.  
  165. void _main ()
  166. {
  167.   struct DosPacket *packet;
  168.   struct Process *proc = (struct Process *) FindTask (NULL);
  169.  
  170.   PktPort = &proc->pr_MsgPort;
  171.   NewList (&HanList);
  172.   Initialize ();
  173.  
  174.   Running = TRUE;
  175.   AllocCnt = 0;
  176.  
  177. #ifdef DEBUG
  178.   kprintf("Init\n");
  179. #endif
  180.  
  181.   /*
  182.    *        Main Loop
  183.    */
  184.  
  185.   while(Running) {
  186.     struct Message *msg;
  187.  
  188.     while ((msg = GetMsg (PktPort)) == NULL)
  189.       Wait (1 << PktPort->mp_SigBit);
  190.     packet = (struct DosPacket *) msg->mn_Node.ln_Name;
  191.  
  192.     /*
  193.      *  default return value
  194.      */
  195.  
  196.     packet->dp_Res1 = DOS_TRUE;
  197.     packet->dp_Res2 = 0;
  198.  
  199.     /*
  200.      *  switch on packet
  201.      */
  202.  
  203.     switch (packet->dp_Type) {
  204.  
  205.       case ACTION_DIE:        /*  ??? */
  206.       {
  207.         break;
  208.       }
  209.  
  210.       /***********************************************************************/
  211.  
  212.       case ACTION_FINDUPDATE: /*  FileHandle,Lock,Name        Bool        */
  213.       case ACTION_FINDINPUT:  /*  FileHandle,Lock,Name        Bool        */
  214.       case ACTION_FINDOUTPUT: /*  FileHandle,Lock,Name        Bool        */
  215.       {
  216.         struct FileHandle *fh = BTOC (packet->dp_Arg1);
  217.         unsigned char *base = BTOC (packet->dp_Arg3);
  218.         int len = *base;
  219.         char buf[128];
  220.         struct HandlerData *data;
  221.         int unit = AHI_DEFAULT_UNIT;
  222.  
  223.         // Skip volume name and ':'
  224.  
  225.         while(*++base != ':')
  226.           --len;
  227.         ++base;
  228.  
  229.         {
  230.           // Convert /'s to blanks
  231.  
  232.           char *p = base;
  233.  
  234.           while(*++p)
  235.             if(*p == '/')
  236.               *p = ' ';
  237.         }
  238.  
  239.         if (len >= sizeof (buf))
  240.           len = sizeof (buf) - 1;
  241.  
  242.         strncpy (buf, base, len - 1);
  243.         buf[len - 1] = '\n';
  244.         buf[len] = 0;
  245.  
  246. #ifdef DEBUG
  247.         kprintf("ACTION_FIND#?: %s\n", (char *) buf);
  248. #endif
  249.  
  250.         data = AllocVec(sizeof(struct HandlerData), MEMF_PUBLIC | MEMF_CLEAR);
  251.         if(! data) {
  252.           packet->dp_Res1 = DOS_FALSE;
  253.           packet->dp_Res2 = ERROR_NO_FREE_STORE;
  254.           break;
  255.         }
  256.  
  257.         if(packet->dp_Res2 = ParseArgs(data, (char *) buf)) {
  258.           FreeHData(data);
  259.           packet->dp_Res1 = DOS_FALSE;
  260.           break;
  261.         }
  262.  
  263.         if(data->args.unit) {
  264.           unit = *data->args.unit;
  265.         }
  266.  
  267.         if(packet->dp_Res2 = AllocAudio(unit)) {
  268.           FreeAudio();
  269.           FreeHData(data);
  270.           packet->dp_Res1 = DOS_FALSE;
  271.           break;
  272.         }
  273.  
  274.  
  275.         fh->fh_Arg1 = (ULONG) data;
  276.         fh->fh_Port = (struct MsgPort *) DOS_TRUE;
  277.         break;
  278.       }
  279.  
  280.       /***********************************************************************/
  281.  
  282.       case ACTION_READ:        /*  FHArg1,CPTRBuffer,Length    ActLength   */
  283.       {
  284.  
  285.         /*
  286.          *   Reading is straightforward except for handling EOF... We
  287.          *  must guarentee a return value of 0 (no bytes left) before
  288.          *  beginning to return EOFs (-1's).  If we return a negative
  289.          *  number right off programs like COPY will assume a failure
  290.          *  (if AUDIO: is the source) and delete the destination file.
  291.          *
  292.          *  The basic idea is to feed the packets from one buffer while
  293.          *  recording asyncroniously to the other. When we have read
  294.          *  the buffer, we wait until the other is filled, and switch
  295.          *  buffer pointers.
  296.          */
  297.  
  298.         struct HandlerData *data = (struct HandlerData *) packet->dp_Arg1;
  299.         UBYTE *dest   = (void *) packet->dp_Arg2;
  300.         LONG   length, filled;
  301.  
  302. #ifdef DEBUG
  303.         kprintf("ACTION_READ: 0x%08lx, %ld\n", packet->dp_Arg2, packet->dp_Arg3);
  304. #endif
  305.  
  306.         if(! data->initialized) {
  307.           packet->dp_Res2 = InitHData(data);
  308.           if(packet->dp_Res2) {
  309.             packet->dp_Res1 = -1;
  310.             break;
  311.           }
  312.         }
  313.  
  314.         length = filled = min(data->totallength, packet->dp_Arg3);
  315.  
  316.         if(length <= 0) {
  317.           packet->dp_Res1 = length;
  318.           data->totallength = -1;
  319.           break;
  320.         }
  321.  
  322.         if(data->buffer1 == NULL) {
  323.  
  324.           data->buffer1 = AllocVec(data->buffersize, MEMF_PUBLIC);
  325.           data->buffer2 = AllocVec(data->buffersize, MEMF_PUBLIC);
  326.           data->readreq    = AllocVec(sizeof (struct AHIRequest), MEMF_PUBLIC);
  327.  
  328.           if((data->buffer1 == NULL)
  329.           || (data->buffer2 == NULL)
  330.           || (data->readreq    == NULL)) {
  331.             packet->dp_Res1 = -1;
  332.             packet->dp_Res2 = ERROR_NO_FREE_STORE;
  333.             break;
  334.           }
  335.  
  336.           CopyMem(AHIio, data->readreq, sizeof (struct AHIRequest));
  337.  
  338.           // Fill buffer 2
  339.           // Note that io_Offset is always 0 the first time
  340.  
  341.           data->readreq->ahir_Std.io_Command  = CMD_READ;
  342.           data->readreq->ahir_Std.io_Data     = data->buffer2;
  343.           data->readreq->ahir_Std.io_Length   = data->buffersize;
  344.           data->readreq->ahir_Std.io_Offset   = 0;
  345.           data->readreq->ahir_Type            = data->type;
  346.           data->readreq->ahir_Frequency       = data->freq;
  347.           data->readreq->ahir_Volume          = data->vol;
  348.           data->readreq->ahir_Position        = data->pos;
  349.           SendIO((struct IORequest *) data->readreq);
  350.   
  351.           // Force buffer switch filling of the other buffer
  352.  
  353.           data->length = data->offset = 0;
  354.  
  355.           // Check if we should write a header first
  356.  
  357.           if(data->format == AIFF) {
  358.             if(length < sizeof(struct AIFFHeader)) {
  359.               packet->dp_Res1 = -1;
  360.               packet->dp_Res2 = ERROR_BAD_NUMBER;
  361.               break;
  362.             }
  363.  
  364.             FillAIFFheader(data);
  365.  
  366.             CopyMem(&AIFFHeader, dest, sizeof(struct AIFFHeader)); 
  367.             dest              += sizeof(struct AIFFHeader);
  368.             length            -= sizeof(struct AIFFHeader);
  369.           }
  370.  
  371.           else if(data->format == AIFC) {
  372.             if(length < sizeof(struct AIFCHeader)) {
  373.               packet->dp_Res1 = -1;
  374.               packet->dp_Res2 = ERROR_BAD_NUMBER;
  375.               break;
  376.             }
  377.  
  378.             FillAIFCheader(data);
  379.  
  380.             CopyMem(&AIFCHeader, dest, sizeof(struct AIFCHeader)); 
  381.             dest              += sizeof(struct AIFCHeader);
  382.             length            -= sizeof(struct AIFCHeader);
  383.           }
  384.         }
  385.  
  386.  
  387.         while(length > 0) {
  388.           LONG thislength;
  389.         
  390.           if(data->offset >= data->length) {
  391.             void *temp;
  392.  
  393.             temp          = data->buffer1;
  394.             data->buffer1 = data->buffer2;
  395.             data->buffer2 = temp;
  396.  
  397.             if(WaitIO((struct IORequest *) data->readreq)) {
  398.               packet->dp_Res1 = -1;
  399.               if(data->readreq->ahir_Std.io_Error == AHIE_HALFDUPLEX) {
  400.                 packet->dp_Res2 = ERROR_OBJECT_IN_USE;
  401.               }
  402.               else {
  403.                 packet->dp_Res2 = ERROR_READ_PROTECTED;
  404.               }
  405.               break;
  406.             }
  407.  
  408.             data->length = data->readreq->ahir_Std.io_Actual;
  409.             data->offset = 0;
  410.  
  411.             data->readreq->ahir_Std.io_Command = CMD_READ;
  412.             data->readreq->ahir_Std.io_Data    = data->buffer2;
  413.             data->readreq->ahir_Std.io_Length  = data->buffersize;
  414.             data->readreq->ahir_Type           = data->type;
  415.             data->readreq->ahir_Frequency      = data->freq;
  416.             data->readreq->ahir_Volume         = data->vol;
  417.             data->readreq->ahir_Position       = data->pos;
  418.             SendIO((struct IORequest *) data->readreq);
  419.           } /* if */
  420.  
  421.           thislength = min(data->length - data->offset, length);
  422.           CopyMem(data->buffer1 + data->offset, dest, thislength); 
  423.           dest              += thislength;
  424.           length            -= thislength;
  425.           data->offset      += thislength;
  426.           data->totallength -= thislength;
  427.         } /* while */
  428.  
  429.         if(packet->dp_Res2 == 0) {
  430.           packet->dp_Res1 = filled;
  431.         }
  432.         break;
  433.  
  434.       } /* ACTION_READ */
  435.  
  436.       /***********************************************************************/
  437.  
  438.       case ACTION_WRITE:        /*  FHArg1,CPTRBuffer,Length    ActLength   */
  439.       {
  440.         struct HandlerData *data  = (struct HandlerData *) packet->dp_Arg1;
  441.         UBYTE *src    = (void *) packet->dp_Arg2;
  442.         LONG   length = packet->dp_Arg3, filled;
  443.  
  444. #ifdef DEBUG
  445.         kprintf("ACTION_WRITE: 0x%08lx, %ld\n", packet->dp_Arg2, packet->dp_Arg3);
  446. #endif
  447.  
  448.         if(data->buffer1 == NULL) {
  449.           // Check headers?
  450.  
  451.           switch(data->args.format) {
  452.             case AIFF:
  453.               if((((ULONG *) src)[0] != ID_FORM)
  454.               || (((ULONG *) src)[2] != ID_AIFF)) {
  455.                 packet->dp_Res2 = ERROR_OBJECT_WRONG_TYPE;
  456.               }
  457.               break;
  458.  
  459.             case AIFC:
  460.               if((((ULONG *) src)[0] != ID_FORM)
  461.               || (((ULONG *) src)[2] != ID_AIFC)) {
  462.                 packet->dp_Res2 = ERROR_OBJECT_WRONG_TYPE;
  463.               }
  464.               break;
  465.  
  466.             case 0:
  467.               if(((ULONG *) src)[0] == ID_FORM) {
  468.                 if(((ULONG *) src)[2] == ID_AIFF) {
  469.                   data->args.format = AIFF;
  470.                 }
  471.                 else if(((ULONG *) src)[2] == ID_AIFC) {
  472.                   data->args.format = AIFC;
  473.                 }
  474.               }
  475.               break;
  476.             
  477.             default:
  478.               break;
  479.           }
  480.  
  481.           if(packet->dp_Res2) {
  482.             packet->dp_Res1 = -1;
  483.             break;
  484.           }
  485.  
  486.           if((data->args.format == AIFF) || (data->args.format == AIFC)) {
  487.             LONG skiplen = 0;
  488.  
  489.             skiplen = ReadCOMMchunk(data, src, length);
  490.             src    += skiplen;
  491.             length -= skiplen;
  492.           }
  493.  
  494.           if(packet->dp_Res2 = InitHData(data)) {
  495.             packet->dp_Res1 = -1;
  496.             break;
  497.           }
  498.  
  499.           data->writing = TRUE;
  500.  
  501.           data->buffer1 = AllocVec(data->buffersize, MEMF_PUBLIC);
  502.           data->buffer2 = AllocVec(data->buffersize, MEMF_PUBLIC);
  503.  
  504.           if((data->buffer1 == NULL) || (data->buffer2 == NULL)) {
  505.             packet->dp_Res1 = -1;
  506.             packet->dp_Res2 = ERROR_NO_FREE_STORE;
  507.             break;
  508.           }
  509.  
  510.           data->offset = 0;
  511.           data->length = (data->buffersize / AHI_SampleFrameSize(data->type))
  512.                           * AHI_SampleFrameSize(data->type);
  513.  
  514.         }
  515.  
  516.         length = min(data->totallength, length);
  517.         filled = min(data->totallength, packet->dp_Arg3);
  518.  
  519.         while(length > 0) {
  520.           LONG thislength;
  521.         
  522.           if(data->offset >= data->length) {
  523.             packet->dp_Res2 = PlayAndSwap(data, data->length);
  524.             if(packet->dp_Res2) {
  525.               packet->dp_Res1 = -1;
  526.               break;
  527.             }
  528.           }
  529.  
  530.           thislength = min(data->length - data->offset, length);
  531.           CopyMem(src, data->buffer1 + data->offset, thislength); 
  532.           src               += thislength;
  533.           length            -= thislength;
  534.           data->offset      += thislength;
  535.           data->totallength -= thislength;
  536.  
  537.         } /* while */
  538.  
  539.         if(packet->dp_Res2 == 0) {
  540.           packet->dp_Res1 = filled;
  541.         }
  542.         break;
  543.       }
  544.  
  545.       /***********************************************************************/
  546.  
  547.       case ACTION_END:        /*  FHArg1                      Bool:TRUE   */
  548.       {
  549.         struct HandlerData *data = (struct HandlerData *) packet->dp_Arg1;
  550.  
  551. #ifdef DEBUG
  552.         kprintf("ACTION_END\n");
  553. #endif
  554.  
  555.         // Abort any reading requests
  556.  
  557.         if(data->readreq) {
  558.           AbortIO((struct IORequest *) data->readreq);
  559.           WaitIO((struct IORequest *) data->readreq);
  560.         }
  561.  
  562.         // Finish any playing requests
  563.  
  564.         if(data->writing) {
  565.           PlayAndSwap(data, data->offset);
  566.  
  567.           if(data->writereq1) {
  568.             WaitIO((struct IORequest *) data->writereq1);
  569.           }
  570.           if(data->writereq2) {
  571.             WaitIO((struct IORequest *) data->writereq2);
  572.           }
  573.         }
  574.  
  575.         FreeHData(data);
  576.         FreeAudio();
  577.  
  578.  
  579.         break;
  580.       }
  581.  
  582.       /***********************************************************************/
  583.  
  584.       case ACTION_IS_FILESYSTEM:
  585.         packet->dp_Res1 = DOS_FALSE;
  586.         break;
  587.  
  588.       /***********************************************************************/
  589.  
  590.       default:
  591.         packet->dp_Res1 = DOS_FALSE;
  592.         packet->dp_Res2 = ERROR_ACTION_NOT_KNOWN;
  593.         break;
  594.  
  595.     } /* switch */
  596.  
  597.     if(AllocCnt == 0)
  598.       Running = FALSE;
  599.  
  600.     if (packet) {
  601.       returnpacket (packet);
  602. #ifdef DEBUG
  603.       kprintf("Retured packet\n");
  604. #endif
  605.     }
  606.  
  607.   } /* for */
  608.  
  609. #ifdef DEBUG
  610.   kprintf("Dying..!\n");
  611. #endif
  612.   UnInitialize();
  613.   _exit (0);
  614. }
  615.  
  616.  
  617. /******************************************************************************
  618. **** PlayAndSwap **************************************************************
  619. ******************************************************************************/
  620.  
  621. /*
  622.  *  Starts to play the current buffer. Handles double buffering.
  623.  */
  624.  
  625. LONG PlayAndSwap(struct HandlerData *data, LONG length) {
  626.   void *temp;
  627.  
  628.   temp          = data->buffer1;
  629.   data->buffer1 = data->buffer2;
  630.   data->buffer2 = temp;
  631.  
  632.   temp            = data->writereq1;
  633.   data->writereq1 = data->writereq2;
  634.   data->writereq2 = temp;
  635.  
  636.  
  637.   if(data->writereq1 == NULL) {
  638.     data->writereq1 = AllocVec(sizeof (struct AHIRequest), MEMF_PUBLIC);
  639.  
  640.     if(data->writereq1 == NULL) {
  641.       return ERROR_NO_FREE_STORE;
  642.     }
  643.  
  644.     CopyMem(AHIio, data->writereq1, sizeof (struct AHIRequest));
  645.   }
  646.  
  647.   data->offset = 0;
  648.  
  649.   data->writereq1->ahir_Std.io_Message.mn_Node.ln_Pri = data->priority;
  650.   data->writereq1->ahir_Std.io_Command = CMD_WRITE;
  651.   data->writereq1->ahir_Std.io_Data    = data->buffer2;
  652.   data->writereq1->ahir_Std.io_Length  = length;
  653.   data->writereq1->ahir_Std.io_Offset  = 0;
  654.   data->writereq1->ahir_Type           = data->type;
  655.   data->writereq1->ahir_Frequency      = data->freq;
  656.   data->writereq1->ahir_Volume         = data->vol;
  657.   data->writereq1->ahir_Position       = data->pos;
  658.   data->writereq1->ahir_Link           = data->writereq2;
  659.   SendIO((struct IORequest *) data->writereq1);
  660.  
  661.   if(data->writereq2) {
  662.     if(WaitIO((struct IORequest *) data->writereq2)) {
  663.       if(data->writereq2->ahir_Std.io_Error == AHIE_HALFDUPLEX) {
  664.         return ERROR_OBJECT_IN_USE;
  665.       }
  666.       else {
  667.         return ERROR_WRITE_PROTECTED;
  668.       }
  669.     }
  670.   }
  671.  
  672.   return 0;
  673. }
  674.  
  675.  
  676. /******************************************************************************
  677. **** extended2long ************************************************************
  678. ******************************************************************************/
  679.  
  680. /*
  681.  *  This function translates Apples SANE Extended  used in AIFF/AIFC files
  682.  *  to a LONG. Stolen from Olaf `Olsen' Barthel's AIFF datatype.
  683.  */
  684.  
  685.  
  686. long extended2long(extended *ex)
  687. {
  688.   unsigned long mantissa;
  689.   long exponent,sign;
  690.  
  691.     // We only need 32 bits precision
  692.  
  693.   mantissa = ex->mantissa[0];
  694.  
  695.     // Is the mantissa positive or negative?
  696.  
  697.   exponent = ex->exponent;
  698.  
  699.   if(exponent & 0x8000)
  700.     sign = -1;
  701.   else
  702.     sign =  1;
  703.  
  704.     // Unbias the exponent
  705.  
  706.   exponent = (exponent & 0x7FFF) - 0x3FFF;
  707.  
  708.     // If the exponent is negative, set the mantissa to zero
  709.  
  710.   if(exponent < 0)
  711.     mantissa = 0;
  712.   else
  713.   {
  714.       // Special meaning?
  715.  
  716.     exponent -= 31;
  717.  
  718.       // Overflow?
  719.  
  720.     if(exponent > 0)
  721.       mantissa = 0x7FFFFFFF;
  722.     else
  723.       mantissa >>= -exponent; // Let the point float...
  724.   }
  725.  
  726.     // That's all...
  727.  
  728.   return(sign * (long)mantissa);
  729. }
  730.  
  731.  
  732. /******************************************************************************
  733. **** ulong2extended ***********************************************************
  734. ******************************************************************************/
  735.  
  736. /*
  737.  *  This function translates an ULONG to Apples SANE Extended
  738.  *  used in AIFF/AIFC files.
  739.  */
  740.  
  741. void ulong2extended (ULONG in, extended *ex)
  742. {
  743.   ex->exponent=31+16383;
  744.   ex->mantissa[1]=0;
  745.   while(!(in & 0x80000000))
  746.   {
  747.     ex->exponent--;
  748.     in<<=1;
  749.   }
  750.   ex->mantissa[0]=in;
  751. }
  752.  
  753.  
  754. /******************************************************************************
  755. **** FillAIFFheader ***********************************************************
  756. ******************************************************************************/
  757.  
  758. void FillAIFFheader(struct HandlerData *data) {
  759.  
  760.   AIFFHeader.FORMsize = sizeof(AIFFHeader) + data->totallength - 8;
  761.   AIFFHeader.COMMchunk.numChannels = data->channels;
  762.   AIFFHeader.COMMchunk.numSampleFrames = 
  763.       data->totallength / AHI_SampleFrameSize(data->type);
  764.   AIFFHeader.COMMchunk.sampleSize = data->bits;
  765.   ulong2extended(data->freq, &AIFFHeader.COMMchunk.sampleRate);
  766.   AIFFHeader.SSNDsize = sizeof(SampledSoundHeader) + data->totallength;
  767. }
  768.  
  769.  
  770. /******************************************************************************
  771. **** FillAIFCheader ***********************************************************
  772. ******************************************************************************/
  773.  
  774. void FillAIFCheader(struct HandlerData *data) {
  775.  
  776.   AIFCHeader.FORMsize = sizeof(AIFCHeader) + data->totallength - 8;
  777.   AIFCHeader.COMMchunk.numChannels = data->channels;
  778.   AIFCHeader.COMMchunk.numSampleFrames = 
  779.       data->totallength / AHI_SampleFrameSize(data->type);
  780.   AIFCHeader.COMMchunk.sampleSize = data->bits;
  781.   ulong2extended(data->freq, &AIFCHeader.COMMchunk.sampleRate);
  782.   AIFCHeader.SSNDsize = sizeof(SampledSoundHeader) + data->totallength;
  783. }
  784.  
  785.  
  786. /******************************************************************************
  787. **** ReadCOMMchunk ************************************************************
  788. ******************************************************************************/
  789.  
  790. LONG ReadCOMMchunk(struct HandlerData *data, UBYTE *buffer, LONG length) {
  791.   UWORD *src = (UWORD *) buffer;
  792.   LONG   len = (length >> 1) - 2;
  793.   ExtCommonChunk *common;
  794.  
  795.   while(len > 0) {
  796.     if(((ULONG *) src)[0] == ID_COMM) {
  797.       common = (ExtCommonChunk *) (src + 4);
  798.       data->channels    = common->numChannels;
  799.       data->bits        = common->sampleSize;
  800.       data->totallength = common->numSampleFrames * common->numChannels *
  801.           (data->bits <= 8 ? 1 : (data->bits <= 16 ? 2 : (data->bits <= 32 ? 4 : 0)));
  802.       data->freq = extended2long(&common->sampleRate);
  803.  
  804.       if(!data->args.channels)
  805.         data->args.channels = &data->channels;
  806.       if(!data->args.bits)
  807.         data->args.bits     = &data->bits;
  808.       if(!data->args.length)
  809.         data->args.length   = &data->totallength;
  810.       if(!data->args.freq)
  811.         data->args.freq     = &data->freq;
  812.     }
  813.     else if(((ULONG *) src)[0] == ID_SSND) {
  814.       src += 8;
  815.       break;
  816.     }
  817.     src++;
  818.     len--;
  819.   }
  820.   return (LONG) src - (LONG) buffer;
  821. }
  822.  
  823. /******************************************************************************
  824. **** AllocAudio ***************************************************************
  825. ******************************************************************************/
  826.  
  827. /*
  828.  *  If the device isn't already open, open it now
  829.  */
  830.  
  831. long AllocAudio(int unit) {
  832.   long rc = 0;
  833.  
  834.   if(++AllocCnt == 1) {
  835.     if(AHImp=CreateMsgPort()) {
  836.       if(AHIio=(struct AHIRequest *)CreateIORequest(AHImp,sizeof(struct AHIRequest))) {
  837.         AHIio->ahir_Version = 4;
  838.         AHIDevice=OpenDevice(AHINAME,unit,(struct IORequest *)AHIio,NULL);
  839.       }
  840.     }
  841.  
  842.     if(AHIDevice) {
  843.       rc = ERROR_OBJECT_NOT_FOUND;
  844.     }
  845.     else {
  846.       AHIBase=(struct Library *)AHIio->ahir_Std.io_Device;
  847.     }
  848.   }
  849.   return rc;
  850. }
  851.  
  852.  
  853. /******************************************************************************
  854. **** FreeAudio ****************************************************************
  855. ******************************************************************************/
  856.  
  857. /*
  858.  *  If we're the last user, close the device now
  859.  */
  860.  
  861. void FreeAudio(void)
  862. {
  863.   if(--AllocCnt == 0) {
  864.     if(AHIDevice == 0)
  865.       CloseDevice((struct IORequest *)AHIio);
  866.     AHIDevice = -1;
  867.     DeleteIORequest((struct IORequest *)AHIio);
  868.     AHIio = NULL;
  869.     DeleteMsgPort(AHImp);
  870.     AHImp = NULL;
  871.   }
  872. }
  873.  
  874.  
  875. /******************************************************************************
  876. **** ParseArgs ****************************************************************
  877. ******************************************************************************/
  878.  
  879. /*
  880.  *  Fill out argument array. Returns 0 on success, else a DOS error code.
  881.  */
  882.  
  883. long ParseArgs(struct HandlerData *data, char *initstring) {
  884.   long rc = 0;
  885.  
  886.   data->rdargs = (struct RDArgs *) AllocDosObjectTags(DOS_RDARGS, TAG_DONE);
  887.   if(data->rdargs)
  888.   {
  889.     data->rdargs->RDA_Source.CS_Buffer = initstring;
  890.     data->rdargs->RDA_Source.CS_Length = strlen(initstring);
  891.     data->rdargs->RDA_Source.CS_CurChr = 0;
  892.     data->rdargs->RDA_Flags |= RDAF_NOPROMPT;
  893.  
  894.     data->rdargs2 = ReadArgs(
  895.       "B=BITS/K/N,C=CHANNELS/K/N,F=FREQUENCY/K/N,T=TYPE/K,V=VOLUME/K/N,P=POSITION/K/N,"
  896.       "PRI=PRIORITY/K/N,L=LENGTH/K/N,S=SECONDS/K/N,BUF=BUFFER/K/N,UNIT/K/N",
  897.       (LONG *) &data->args, data->rdargs);
  898.  
  899.     if(data->rdargs2 != NULL) {
  900.  
  901.  
  902.       if(! data->args.type) {
  903.         data->args.format = 0;
  904.       }
  905.       else if(Stricmp("SIGNED", data->args.type) == 0) {
  906.         data->args.format = SIGNED;
  907.       }
  908.       else if(Stricmp("AIFF", data->args.type) == 0) {
  909.         data->args.format = AIFF;
  910.       }
  911.       else if(Stricmp("AIFC", data->args.type) == 0) {
  912.         data->args.format = AIFC;
  913.       }
  914.       else {
  915.         rc = ERROR_BAD_TEMPLATE;
  916.       }
  917.     }
  918.     else
  919.       rc = ERROR_BAD_TEMPLATE;
  920.  
  921.   }
  922.   else
  923.     rc = ERROR_NO_FREE_STORE;
  924.  
  925.   return rc;
  926. }
  927.  
  928.  
  929. /******************************************************************************
  930. **** InitHData ****************************************************************
  931. ******************************************************************************/
  932.  
  933. /*
  934.  *  Initialize the HandlerData data structure, based on the args structure
  935.  *  (see ParseArgs()). Returns 0 on success, else a DOS error code.
  936.  */
  937.  
  938. #define S8bitmode      0
  939. #define S16bitmode     1
  940. #define S32bitmode     8
  941.  
  942. #define Sstereoflag    2
  943.  
  944. long InitHData(struct HandlerData *data) {
  945.   ULONG bits = 8, channels = 1, freq = 8000;
  946.   LONG  volume = 100, position = 0, priority = 0, 
  947.         length = MAXINT, buffersize = 32768;
  948.   long rc = 0;
  949.  
  950.   data->initialized = TRUE;
  951.  
  952.   // Fill in default values
  953.  
  954.   if(!data->args.bits)
  955.     data->args.bits = &bits;
  956.   if(!data->args.channels)
  957.     data->args.channels = &channels;
  958.   if(!data->args.freq)
  959.     data->args.freq = &freq;
  960.   if(!data->args.volume)
  961.     data->args.volume = &volume;
  962.   if(!data->args.position)
  963.     data->args.position = &position;
  964.   if(!data->args.priority)
  965.     data->args.priority = &priority;
  966.   if(!data->args.length)
  967.     data->args.length = &length;
  968.   if(!data->args.buffersize)
  969.     data->args.buffersize = &buffersize;
  970.  
  971.   if(!data->args.format)
  972.     data->args.format = SIGNED;
  973.  
  974.   // 8, 16 or 32 bit
  975.  
  976.   if(*data->args.bits <= 8)
  977.     data->type = S8bitmode;
  978.   else if(*data->args.bits <= 16)
  979.     data->type = S16bitmode;
  980.   else if(*data->args.bits <= 32)
  981.     data->type = S32bitmode;
  982.   else {
  983.     rc = ERROR_OBJECT_WRONG_TYPE;
  984.     goto quit;
  985.   }
  986.  
  987.   // Mono or stereo
  988.  
  989.   if((*data->args.channels > 2) || (*data->args.channels < 1)) {
  990.     rc = ERROR_OBJECT_WRONG_TYPE;
  991.     goto quit;
  992.   }
  993.  
  994.   if(*data->args.channels == 2)
  995.     data->type |= Sstereoflag;
  996.  
  997.   data->bits     = *data->args.bits;
  998.   data->channels = *data->args.channels;
  999.   data->freq     = *data->args.freq;
  1000.   data->vol      = *data->args.volume * 0x10000 / 100;
  1001.   { // Don't ask why... :(
  1002.     LONG a;
  1003.     a = *data->args.position * 0x8000;
  1004.     a = a / 100 + 0x8000;
  1005.     data->pos      = a;
  1006.   }
  1007.   data->priority = *data->args.priority;
  1008.  
  1009.   if(data->args.seconds) {
  1010.     data->totallength = *data->args.seconds * data->freq 
  1011.                         * AHI_SampleFrameSize(data->type);
  1012.   }
  1013.   else {
  1014.     data->totallength = (*data->args.length / AHI_SampleFrameSize(data->type))
  1015.                         * AHI_SampleFrameSize(data->type);
  1016.   }
  1017.  
  1018.   data->format = data->args.format;
  1019.  
  1020.   switch(data->format) {
  1021.     case AIFF:
  1022.     case AIFC:
  1023.       data->totallength = data->totallength & ~1;    // Make even
  1024.       break;
  1025.   }
  1026.  
  1027.   data->buffersize = *data->args.buffersize;
  1028.  
  1029. quit:
  1030.   return rc;
  1031. }
  1032.  
  1033.  
  1034.  
  1035.  
  1036.  
  1037.  
  1038.  
  1039.  
  1040.  
  1041.  
  1042.  
  1043. /******************************************************************************
  1044. **** FreeHData ****************************************************************
  1045. ******************************************************************************/
  1046.  
  1047. /*
  1048.  *   Deallocate the HandlerData structure
  1049.  */
  1050.  
  1051. void FreeHData(struct HandlerData *data) {
  1052.   if(data) {
  1053.     if(data->rdargs2)
  1054.       FreeArgs(data->rdargs2);
  1055.     if(data->rdargs);
  1056.     FreeDosObject(DOS_RDARGS, data->rdargs);
  1057.  
  1058.     FreeVec(data->buffer1);
  1059.     FreeVec(data->buffer2);
  1060.     FreeVec(data->readreq);
  1061.     FreeVec(data->writereq1);
  1062.     FreeVec(data->writereq2);
  1063.     FreeVec(data);
  1064.   }
  1065. }
  1066.  
  1067.  
  1068. /******************************************************************************
  1069. **** returnpacket *************************************************************
  1070. ******************************************************************************/
  1071.  
  1072. /*
  1073.  *  PACKET ROUTINES.  Dos Packets are in a rather strange format as you
  1074.  *  can see by this and how the PACKET structure is extracted in the
  1075.  *  GetMsg() of the main routine.
  1076.  */
  1077.  
  1078. void returnpacket (struct DosPacket *packet) {
  1079.   struct Message *mess;
  1080.   struct MsgPort *replyPort;
  1081.  
  1082.   replyPort = packet->dp_Port;
  1083.   mess = packet->dp_Link;
  1084.   packet->dp_Port = PktPort;
  1085.   mess->mn_Node.ln_Name = (char *) packet;
  1086.   PutMsg (replyPort, mess);
  1087. }
  1088.  
  1089.  
  1090. /******************************************************************************
  1091. **** Initialize ***************************************************************
  1092. ******************************************************************************/
  1093.  
  1094. /*
  1095.  *  During initialization DOS sends us a packet and sets our dn_SegList
  1096.  *  pointer.  If we set our dn_Task pointer than every Open's go to the
  1097.  *  same handler (this one).  If we set dn_Task to NULL, every Open()
  1098.  *  will create a NEW instance of this process via the seglist, meaning
  1099.  *  our process must be reentrant (i.e. -r option).
  1100.  *
  1101.  *  note: dn_Task points to the MESSAGE PORT portion of the process
  1102.  *  (or your own custom message port).
  1103.  *
  1104.  *  If we clear the SegList then we also force DOS to reload our process
  1105.  *  from disk, but we also need some way of then UnLoadSeg()ing it ourselves,
  1106.  *  which we CANNOT do from this process since it rips our code out from
  1107.  *  under us.
  1108.  */
  1109.  
  1110. void Initialize () {
  1111.   struct DeviceNode *dn;
  1112.   struct Process *proc = (struct Process *) FindTask (NULL);
  1113.   struct DosPacket *packet;
  1114.  
  1115.   /*
  1116.    *        Handle initial message.
  1117.    */
  1118.   
  1119.   struct Message *msg;
  1120.  
  1121.   WaitPort (PktPort);
  1122.   msg = GetMsg (PktPort);
  1123.   packet = (struct DosPacket *) msg->mn_Node.ln_Name;
  1124.  
  1125.   DevNode = dn = BTOC (packet->dp_Arg3);
  1126.   dn->dn_Task = NULL;
  1127.  
  1128.   packet->dp_Res1 = DOS_TRUE;
  1129.   packet->dp_Res2 = 0;
  1130.   returnpacket (packet);
  1131. }
  1132.  
  1133.  
  1134. /******************************************************************************
  1135. **** UnInitialize *************************************************************
  1136. ******************************************************************************/
  1137.  
  1138. void UnInitialize (void) {
  1139.   struct DeviceNode *dn = DevNode;
  1140.  
  1141.   dn->dn_Task = NULL;
  1142. }
  1143.